local FightActionManager = class("FightActionManager")
local FightActor = require("gameLogic.fight.FightActor")
local Vector3 = require("utils.Vector3")
local FightConst = require("const.FightConst")
local FightExcuter = require("gameLogic.fight.FightExcuter")
local BuildHelper = require("gameLogic.fight.BuildHelper")
local PostAction = require("gameLogic.fight.PostAction")
local GameUtils = require("utils.GameUtils")
local SkillShow = require("gameLogic.fightSkill.show.SkillShow")
local BuffShow = require("gameLogic.fightSkill.show.BuffShow")
local SheildShow = require("gameLogic.fightSkill.show.SheildShow")
local BattleReportParser = require("gameLogic.fightSkill.show.BattleReportParser")
local FightHelper = require("gameLogic.fight.FightHelper")

local ENTITY_POS_X = {[-1] = 5, [1] = 3, [2] = 0, [3] = -3, [4] = -5}
local ENTITY_POS_Z = {[1] = 0, [2] = 3, [3] = 6, [4] = 5, [5] = 6.5}

function FightActionManager:ctor()
    self._battleParser = BattleReportParser.new(self)
    self._buffShow = BuffShow.new(self)
    self._sheildShow = SheildShow.new(self)
    self:_initData()
end

function FightActionManager:_initData()
end

function FightActionManager:awake()
end

function FightActionManager:start()
    local monster_team = G_UserData:getGameCache():getFight_monster_team()
    if monster_team == 0 then
        G_UIManager:showTip(Lang.get("战斗错误！没有敌人"))
        return
    end
    self._monster_team = monster_team
    G_UserData:getGameCache():setFight_monster_team(0)
    self._fightActors = {}
    self._reportQueue = {}
    self._fightUI = require("gameLogic.ui.FightUI").new(self)
    self._fightExcuter = FightExcuter.new()
    self:_initHeros()
    self:_initMonsters()
    self:_initListener()
    self:_initBlood()
    self._fightExcuter:start()
    G_Corutine.start(
        function()
            coroutine.yield(CS.UnityEngine.WaitForSeconds(2))
            G_SignalManager:dispatch(SignalConst.EVENT_FIGHT_NEXT)
        end
    )
end

function FightActionManager:_initHeros()
    local heroRes = require("config.hero_res")
    local heros = G_UserData:getBattle():getBattleHeros()
    for row = 1, 2 do
        for col = 1, 3 do
            local index = (row - 1) * 3 + col
            local heroUnit = heros[index]
            if heroUnit then
                local fightEntityId = self._fightExcuter:getFightEntityId()
                local config = heroUnit:getConfig()
                local resCfg = heroRes.get(config.res_id)
                local actor = FightActor.new(resCfg, self, fightEntityId)
                actor:setName(config.name)
                actor:setCamp(FightConst.FRIEND_STANDING)
                actor:setStanding(row, col)
                actor:setElement(config.element)
                local posx = ENTITY_POS_X[col]
                local posz = ENTITY_POS_Z[row]
                actor.transform.parent = self._friendPoint.transform
                actor.transform.localPosition = Vector3.new(posx, 0, posz)
                table.insert(self._fightActors, actor)
                BuildHelper.buildEntity(
                    self._fightExcuter,
                    FightConst.FRIEND_STANDING,
                    col,
                    row,
                    fightEntityId,
                    heroUnit
                )
            end
        end
    end
end

function FightActionManager:_initMonsters()
    local heroRes = require("config.hero_res")
    local monsters = FightHelper.getFightMonsterHeros(self._monster_team)
    for row = 1, 2 do
        for col = 1, 3 do
            local index = (row - 1) * 3 + col
            local monsteridParam = monsters[index]
            if monsteridParam then
                local fightEntityId = self._fightExcuter:getFightEntityId()
                local resCfg = heroRes.get(monsteridParam.cfg.res_id)
                local actor = FightActor.new(resCfg, self, fightEntityId)
                actor:setName(monsteridParam.cfg.name)
                actor:setCamp(FightConst.ENEMY_STANDING)
                actor:setStanding(row, col)
                actor:setElement(monsteridParam.cfg.element)
                local posx = ENTITY_POS_X[col]
                local posz = ENTITY_POS_Z[row]
                actor.transform.parent = self._enemyPoint.transform
                actor.transform.localPosition = Vector3.new(posx, 0, posz)
                actor.transform.localEulerAngles = Vector3.new(0, 0, 0)
                table.insert(self._fightActors, actor)
                BuildHelper.buildMonsterEntity(
                    self._fightExcuter,
                    FightConst.ENEMY_STANDING,
                    col,
                    row,
                    fightEntityId,
                    monsteridParam
                )
            end
        end
    end
end

function FightActionManager:getFightEntityId()
    return self._fightExcuter:getFightEntityId()
end

function FightActionManager:_initBlood()
    local bloods = self._fightExcuter:collectEntityBlood()
    for key, value in pairs(bloods) do
        local keys = string.split(key, "_")
        local values = string.split(value, "/")
        local actor = self:findActorByKeys(keys)
        if actor then
            actor:setBloodValue(tonumber(values[1]), tonumber(values[2]))
        end
    end
end

function FightActionManager:findActorByKeys(keys)
    local camp = tonumber(keys[1])
    local row = tonumber(keys[2])
    local col = tonumber(keys[3])
    return self:findActor({camp = camp, row = row, col = col})
end

function FightActionManager:recycleActor(id)
    for i = 1, #self._fightActors do
        local actor = self._fightActors[i]
        if actor:getId() == id then
            if actor:isCall() then
                table.remove(self._fightActors, i)
                actor:delete()
                return
            end
        end
    end
end

function FightActionManager:callActor(obj)
    local callId = obj.callId
    local cfg = require("config.call_obj").get(callId)
    assert(cfg, "can not found cfg in call_obj by id=" .. callId)
    local actor = FightHelper.actorFactory(cfg, obj, self)
    actor:setCamp(obj.camp)
    if obj.camp == FightConst.FRIEND_STANDING then
        actor.transform.parent = self._friendPoint.transform
    else
        actor.transform.parent = self._enemyPoint.transform
    end
    local posx = ENTITY_POS_X[obj.col]
    local posz = ENTITY_POS_Z[obj.row]
    actor:setCall(true)
    actor.transform.localPosition = Vector3.new(posx, 0, posz)
    actor.transform.localEulerAngles = Vector3.new(0, 0, 0)
    table.insert(self._fightActors, actor)
end

function FightActionManager:getCenterPos()
    local centerPos = self._center.transform.position
    return centerPos
end

function FightActionManager:_initListener()
    self._signalSeeEntityAttr =
        G_SignalManager:add(SignalConst.EVENT_SEE_FIGHT_ENTITY_ATTR, handler(self, self._onEventSeeFightAttr))
    self._signalSkillAttackE =
        G_SignalManager:add(SignalConst.EVENT_SKILL_ATTACK_END, handler(self, self._onEventSkillAttackEnd))
    self._signalSkillAttackA =
        G_SignalManager:add(SignalConst.EVENT_SKILL_ATTACK_AFTER, handler(self, self._onEventSkillAttackAfter))
    self._signalSkillAttackB =
        G_SignalManager:add(SignalConst.EVENT_SKILL_ATTACK_BEFORE, handler(self, self._onEventSkillAttackBefore))
    self._signalFightReport =
        G_SignalManager:add(SignalConst.EVENT_FIGHT_REPORT_DISPATCH, handler(self, self._onEventFightReport))
end

function FightActionManager:onEnable()
end

function FightActionManager:onDisable()
end

function FightActionManager:_onEventSeeFightAttr(id, entityId)
    local entity = self._fightExcuter:getEntityById(entityId)
    local pop = require("view.popup.PopupFightAttrDebug").new(entity)
end

function FightActionManager:_onEventFightReport(id, report)
    self._curReport = nil
    self._curReport = report
    self._fightUI:setRoundText(self._curReport.roundCount)
    self:parseReport()
end

function FightActionManager:_onEventSkillAttackEnd()
end

function FightActionManager:_onEventSkillAttackAfter()
end

function FightActionManager:_onEventSkillAttackBefore()
end

function FightActionManager:update()
    if self._actionSequence then
        self._actionSequence:tick()
        if self._actionSequence:isDone() then
            self._actionSequence:destroy()
            self._actionSequence = nil
            if self._curReport.endFlag and self._curReport.endFlag > 0 then
                self:_actionEnd(self._curReport.endFlag)
            else
                local sequence = DOTween.Sequence()
                sequence:AppendInterval(0.2)
                sequence:AppendCallback(
                    function()
                        G_SignalManager:dispatch(SignalConst.EVENT_FIGHT_NEXT)
                    end
                )
            end
            self._curReport = nil
        end
    end
end

function FightActionManager:_actionEnd(flag)
    local pop = require("view.popup.PopupFightEnd").new(handler(self, self._exitFight))
    if flag == 1 then
        pop:setTip(Lang.get("fight_lose_tip"))
    else
        local awards = G_DropManager:monsterDrop(self._monster_team)
        pop:setTip(Lang.get("fight_win_tip"))
        pop:setReward(awards)
    end
    local sceneId = G_SceneManager:getCurSceneId()
    G_UserData:getGameLogic():c2sMonsterLeaveFight(sceneId, self._monster_team, flag == 1 and 0 or 1)
end

function FightActionManager:_exitFight()
    self:delete()
    G_SignalManager:dispatch(SignalConst.EVENT_EXIT_FIGHT)
    local popup = require("view.popup.FightTransition").new()
    popup:setTip(Lang.get("lang_exit_fight_tip"))
    popup:play(
        function()
        end
    )
end

function FightActionManager:delete()
    for i = 1, #self._fightActors do
        local actor = self._fightActors[i]
        actor:delete()
    end
    self._fightActors = {}
    DOTween.KillAll()
    self._fightExcuter:destroy()
    self._fightExcuter = nil
    GameUtils.destroy(self._fightUI.gameObject)
    GameUtils.destroy(self._root)
end

function FightActionManager:parseReport()
    self._actionSequence = self._battleParser:parse(self._curReport)
end

function FightActionManager:showBuffs(reportBuffs)
    if not reportBuffs then
        return 0
    end
    local time = 0
    for i = 1, #reportBuffs do
        local buffParam = reportBuffs[i]
        local tTime = self._buffShow:show(buffParam)
        if tTime > time then
            time = tTime
        end
    end
    return time
end

function FightActionManager:showBuff(buff)
    if not buff then
        return 0
    end
    local time = self._buffShow:show(buff)
    return time
end

function FightActionManager:showSheilds(reportSheilds)
    if not reportSheilds then
        return 0
    end
    local time = 0
    for i = 1, #reportSheilds do
        local sheild = reportSheilds[i]
        local tTime = self._sheildShow:show(sheild)
        if tTime > time then
            time = tTime
        end
    end
    return time
end

function FightActionManager:showSheild(sheild)
    if not sheild then
        return 0
    end
    local time = self._sheildShow:show(sheild)
    return time
end

function FightActionManager:findActor(data)
    for i = 1, #self._fightActors do
        local actor = self._fightActors[i]
        if actor:getCamp() == data.camp and actor:getRow() == data.row and actor:getCol() == data.col then
            return actor
        end
    end
end

function FightActionManager:findActorbyId(id)
    for i = 1, #self._fightActors do
        local actor = self._fightActors[i]
        if actor:getId() == id then
            return actor
        end
    end
end

function FightActionManager:getActorsByCamp(camp)
    local result = {}
    for i = 1, #self._fightActors do
        local actor = self._fightActors[i]
        if actor:getCamp() == camp and not actor:isDie() then
            table.insert(result, actor)
        end
    end
    return result
end

function FightActionManager:onDestroy()
    self._signalSeeEntityAttr:remove()
    self._signalSeeEntityAttr = nil
    self._signalSkillAttackE:remove()
    self._signalSkillAttackE = nil
    self._signalSkillAttackA:remove()
    self._signalSkillAttackA = nil
    self._signalSkillAttackB:remove()
    self._signalSkillAttackB = nil
    self._signalFightReport:remove()
    self._signalFightReport = nil
end

return FightActionManager
